package xyz.labmem.base.sys.base

import cn.dev33.satoken.exception.NotLoginException
import cn.dev33.satoken.stp.StpUtil
import cn.hutool.core.bean.BeanUtil
import cn.hutool.core.convert.Convert
import cn.hutool.core.date.DateUtil
import com.baomidou.mybatisplus.annotation.TableField
import io.swagger.annotations.Api
import io.swagger.annotations.ApiModelProperty
import org.springframework.web.servlet.ModelAndView
import xyz.labmem.base.core.annotion.DynamicPageColumn
import xyz.labmem.base.core.annotion.DynamicPageColumnMapping
import xyz.labmem.base.core.base.GFBaseEntity
import xyz.labmem.base.core.common.response.PageColumn
import xyz.labmem.base.core.consts.USER_SESSION_KEY
import xyz.labmem.base.core.consts.log
import xyz.labmem.base.core.consts.userKeyPrefix
import xyz.labmem.base.core.result.RU
import xyz.labmem.base.core.tool.getClassAllField
import xyz.labmem.base.core.tool.getKClassAllField
import xyz.labmem.base.core.tool.isNotBlank
import xyz.labmem.base.core.tool.toCamelCase
import xyz.labmem.base.sys.module.log.entity.SysUserOnline
import xyz.labmem.base.sys.module.user.entity.SysUser
import java.lang.Exception
import java.util.*
import java.util.function.Consumer
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
import kotlin.reflect.jvm.javaField

/**
 * @Author 刘天予
 * @Date 2020/12/22 14:03
 */
abstract class BaseController : RU() {

    protected val log = this.log()

    /**
     * 转换Array类型
     *
     * @param source
     * @param c
     * @return
     */
    fun <T> arrayCopyToArray(source: List<T>, c: Class<T>): List<T> {
        val list: MutableList<T> = ArrayList()
        source.forEach(Consumer { s: T ->
            try {
                val o = c.getDeclaredConstructor().newInstance()
                BeanUtil.copyProperties(s, o)
                list.add(o)
            } catch (ignored: Exception) {
            }
        })
        return list
    }

    fun getTag(clazz: Any) = clazz::class.java.getAnnotation(Api::class.java).tags[0]

    fun longToDateString(t: Long?): String? =
        if (t != null) DateUtil.format(DateUtil.parse(t.toString()), "yyyy-MM-dd HH:mm:ss") else null

    fun stringToDateString(t: String?): String? =
        if (t.isNotBlank()) DateUtil.format(DateUtil.parse(t), "yyyy-MM-dd HH:mm:ss") else null

    fun stringDateToLong(t: String?): Long? =
        if (t.isNotBlank()) Convert.toLong(DateUtil.format(DateUtil.parse(t), "yyyyMMddHHmmss")) else null

    companion object {

        //获取当前登录用户
        fun getLoginUser(): SysUser {
            return StpUtil.getSession().getModel(USER_SESSION_KEY, SysUser::class.java)
                ?: throw NotLoginException.newInstance("NotFound", "-6")
        }
        //获取当前用户
        fun getOnlineUser(): SysUserOnline? {
            return StpUtil.getSession().getModel(userKeyPrefix+StpUtil.getTokenValue(), SysUserOnline::class.java)
                ?: null
        }
        //根据登录ID获取指定在线登录用户
        fun getOnlineUserByLoginId(loginId:String): SysUserOnline? {
            var tokenValue = StpUtil.getTokenValueByLoginId(loginId)
            return StpUtil.getSessionByLoginId(loginId).getModel(userKeyPrefix+tokenValue, SysUserOnline::class.java)
                ?: null
        }
        //根据token获取指定在线登录用户
        fun getOnlineUserByToken(tokenValue:String): SysUserOnline? {
            var loginId  = StpUtil.getLoginIdByToken(tokenValue)
            return StpUtil.getSessionByLoginId(loginId).getModel(userKeyPrefix+tokenValue, SysUserOnline::class.java)
                ?: null
        }
        /**
         * 页面跳转
         */
        fun jumpPage(path: String?): ModelAndView {
            val modelAndView = ModelAndView()
            modelAndView.viewName = path
            return modelAndView
        }

        /**
         * 获取当前登录用户的信息
         *
         * @return
         */
//        @JvmStatic
//        fun getUser(): SysLoginUser {
//            return LoginContextHolder.me().sysLoginUserUpToDate
//        }

    }

    /**
     * 获取实体所有字段
     */
    fun getFields(clazz: KClass<out GFBaseEntity<*>>, vararg exclude: String): ArrayList<PageColumn> {
        var columns =  ArrayList<PageColumn>()
        clazz.java.getClassAllField().forEach {
            if (!exclude.contains(it.name)) {
                val explain = it.getAnnotation(ApiModelProperty::class.java)
                val tableField = it.getAnnotation(TableField::class.java)
                val an = it.getAnnotation(DynamicPageColumn::class.java)
                columns.add(PageColumn().apply {
                    var key = it.name
                    if (tableField != null) {
                        if (!tableField.exist)
                            return@forEach
                        key = tableField.value
                    }
                    this.key = key
                    value = explain.value
                    if (an != null) {
                        order = if (an.order == 0) columns.size + 1 else an.order
                    }else{
                        order = columns.size + 1
                    }

                })
            }
        }
        columns.sortBy { user ->  user.order}
        return columns
    }
    /**
     * 获取实体所有字段
     */
    fun getFields2(clazz: KClass<out GFBaseEntity<*>>, vararg exclude: String): ArrayList<PageColumn> {
        var columns =  ArrayList<PageColumn>()
        val fields = clazz.java.declaredFields
        fields.forEach {
            if (!exclude.contains(it.name)) {
                val explain = it.getAnnotation(ApiModelProperty::class.java)
                val tableField = it.getAnnotation(TableField::class.java)
                val an = it.getAnnotation(DynamicPageColumn::class.java)
                columns.add(PageColumn().apply {
                    this.key = it.name.toCamelCase()
                    value = explain.value
                    if (an != null) {
                        order = if (an.order == 0) columns.size + 1 else an.order
                    }else{
                        order = columns.size + 1
                    }

                })
            }
        }
        columns.sortBy { user ->  user.order}
        return columns
    }
    /**
     * 获取实体所有字段
     */
    fun getFields1(clazz: KClass<out GFBaseEntity<*>>, vararg exclude: String): Map<String, String> {
        val res = TreeMap<String, String>()
        clazz.java.getClassAllField().forEach {
            if (!exclude.contains(it.name)) {
                val explain = it.getAnnotation(ApiModelProperty::class.java)
                val tableField = it.getAnnotation(TableField::class.java)
                var key = it.name
                if (tableField != null) {
                    if (!tableField.exist)
                        return@forEach
                    key = tableField.value
                }
                res[key] = explain.value
            }
        }
        return res
    }
    fun getKtFields(clazz: KClass<out GFBaseEntity<*>>, vararg exclude: KProperty<*>): Map<String, String> {
        val res = TreeMap<String, String>()
        clazz.getKClassAllField().forEach {
            if (!exclude.contains(it)) {
                val explain = it.javaField!!.getAnnotation(ApiModelProperty::class.java)
                res[it.name] = explain.value
            }
        }
        return res
    }

}